package view.editorview;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreeSelectionModel;

import model.LogicType;
import model.editormodel.ComponentHandler;
import model.editormodel.EditorModel;
import view.UtilityConstants;
import view.commonview.ToolBar;
import view.editorview.ComponentTree.ComponentNode;
import controller.editorcontroller.ComponentPanelPopupListener;
import controller.editorcontroller.ComponentTreeListener;
import controller.editorcontroller.RefreshComponentPanelListener;

/**
 * <b>Implementiert:</b> <code>Observer</code> <br>
 * <b>Erbt</b> <code>JPanel</code> <br>
 * <b>In Verbindung stehende Klassen:</b>
 * <code>ComponentTree, ComponentHandler</code><br>
 * <b>Ueberwachte Klasse: </b> <code>ComponentHandler</code><br>
 * <b>Funktion:</b> Repraesentation der Bauteile<br>
 * <br>
 * Panel, auf der die Baumstruktur liegt, das die im Bauteileordner vorhandenen
 * Bauteile verwaltet. Diese Klasse ueberwacht die Klasse <code>
 * ComponentHandler</code>.
 * 
 * @author Team Locsi
 * 
 */
@SuppressWarnings("serial")
public class ComponentPanel extends JPanel implements Observer {

	/*
	 * Attribute fuer den JTree und im JTree ausgewaehltes Bauteil
	 */
	private JTree tree;
	private ComponentTree mainNode;
	private LogicType actualSelected;
	private String nameSelectedSelfDefined;
	private Component parentForPositioning;
	private JButton refreshButton;

	/**
	 * Dieser Konstruktor erzeugt ein neues <code>ComponentPanel</code>-Objekt.
	 * Dabei wird das <code>ComponentPanel</code> beim
	 * <code>ComponentHandler</code>-Objekt als <code>Observer</code>
	 * angemeldet. Ausserdem wird hier ein neues <code>ComponentTree</code>
	 * -Objekt erzeugt.
	 * 
	 * @param eModel
	 *            <code>EditorModel</code> - Referenz auf das
	 *            <code>EditorModel</code>
	 * @param tools
	 *            <code>ToolBar</code> - Referenz auf die <code>ToolBar</code>
	 */
	public ComponentPanel(EditorModel eModel, ToolBar tools) {
		
		// initialisieren der bauteilauswahlliste
		this.mainNode = new ComponentTree("Bauteile");
		this.tree = new JTree(mainNode);
		this.tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		this.tree.addTreeSelectionListener(new ComponentTreeListener(this,
				tools, this.tree));
		this.tree.setOpaque(false);
		this.tree.setCellRenderer(new MyRenderer());
		this.tree.expandRow(1);
		this.tree.setRowHeight(18);
		this.setLayout(new BorderLayout());
		this.add(Box.createHorizontalStrut(5), BorderLayout.WEST);
		this.add(Box.createVerticalStrut(5), BorderLayout.NORTH);
		this.add(Box.createHorizontalStrut(5), BorderLayout.EAST);
		this.add(this.tree, BorderLayout.CENTER);
		eModel.getComponentHandler().addObserver(this);
		eModel.getComponentHandler().refreshComponentList();
		addRenameEraseListener(eModel);
		getParent(tools);
		createBottomButtons(eModel.getComponentHandler());
	}


	/**
	 * Methode, die einen refresh-Button rechts unten in der Bauteilauswahlliste
	 * erzeugt
	 * 
	 * @param cHandler
	 *            <code>ComponentHandler</code> - Referenz auf den
	 *            <code>ComponentHandler</code>
	 */
	private void createBottomButtons(final ComponentHandler cHandler) {
		JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));


		// erzeugen des Aktualisierungsbutton der Bauteilauswahlliste
		refreshButton = new JButton(new ImageIcon(getClass().getClassLoader().getResource(UtilityConstants.ICON_PATH
				+ "refreshM.png")));
		refreshButton.setOpaque(false);
		refreshButton.setContentAreaFilled(false);
		refreshButton.setMargin(new Insets(0, 0, 0, 0));
		refreshButton.addActionListener(new RefreshComponentPanelListener(
				cHandler));
		panel.add(refreshButton);
		this.add(panel, BorderLayout.SOUTH);
	}

	/**
	 * Sucht den LocsiFrame um die JOptionpanes zentrieren zu koennen.
	 * 
	 * @param tools
	 *            <code>ToolBar</code> - Referenz auf die <code>ToolBar</code>
	 */
	private void getParent(ToolBar tools) {
		Component comp = tools.getParent();
		while (comp != null) {
			comp = ((JComponent) comp).getParent();
			if (comp != null) {
				parentForPositioning = comp;
			}
		}
	}

	/**
	 * Fuegt den Listener auf den JTree mit dem das JPopupMenu mit Rechtsklick
	 * aufgerufen werden kann.
	 * 
	 * @param eModel
	 *            - Referenz auf das EditorModel
	 */
	private void addRenameEraseListener(EditorModel eModel) {
		tree.addMouseListener(new ComponentPanelPopupListener(eModel, tree,
				this, parentForPositioning));
	}

	/**
	 * Diese Methode setzt den aktuell ausgewaehlten Bauteiltyp.
	 * 
	 * @param selected
	 *            <code>LogicType</code> - der ausgewaehlte Bauteiltyp
	 */
	public void setActualSelected(LogicType selected) {
		this.actualSelected = selected;
	}

	/**
	 * Gibt den aktuell ausgewaehlten Bauteiltyp zurueck.
	 * 
	 * @return <code>LogicType</code> - den ausgewaehlten Bauteiltyp null falls
	 *         Leitung ausgewaehlt ist
	 */
	public LogicType getActualSelected() {
		return actualSelected;
	}

	/**
	 * Methode die den Namen des aktuell ausgewahelten selbstdefinierten
	 * Bauteils zurueckgibt (fuer Umbennen wichtig)
	 * 
	 * @return <code>String</code> Name des aktuell ausgewaehlten selbstdefinierten Bauteils
	 */
	public String getNameOfSelectedSelfDefined() {
		return nameSelectedSelfDefined;
	}

	/**
	 * Setzt den Namen des aktuell ausgewaehlten selbstdefinierten Bauteils auf
	 * den uebergebenen Namen (fuer Umbenennen)
	 * 
	 * @param name <code>String</code>
	 *            neuer Name des selbstdefinierten Bauteils
	 */
	public void setNameOfSelectedSelfDefined(String name) {
		this.nameSelectedSelfDefined = name;
	}

	/**
	 * Diese Methode aktualisiert die Bauteilauswahlliste mit Hilfe des
	 * uebergebenen Objekts.
	 */
	@Override
	public void update(Observable o, Object arg) {
		if (arg instanceof List) {

			// entfernen aller bisheriger Komponenten
			mainNode.getSelfDef().removeAllChildren();
			@SuppressWarnings("unchecked")
			List<String> compNames = (List<String>) arg;

			// laedt die uebergebenen selbstdefinierten bauteile in die
			// bauteilauswahlliste unter der rubrik 'selbstdefinierte bauteile'
			for (String string : compNames) {
				mainNode.getSelfDef().add(
						mainNode.new ComponentNode(LogicType.SELFDEFINED,
								string));
			}
			((DefaultTreeModel) tree.getModel()).reload((TreeNode) mainNode
					.getSelfDef());
		}
	}

	/**
	 * <b>Erbt:</b> DefaultTreeCellRenderer <br>
	 * <b>Funktion</b>: Dient zur optischen Darstellung der Knoten des
	 * <code>ComponentTree</code>
	 * 
	 * @author Team Locsi
	 * 
	 */
	private class MyRenderer extends DefaultTreeCellRenderer {

		/**
		 * Dieser Konstruktor erzeugt ein neues <code>MyRenderer</code>-Objekt.
		 */
		public MyRenderer() {
		}

		/**
		 * Diese Methode dient zur optischen Darstellung der Knoten des
		 * <code>ComponentTree</code>.
		 */
		@Override
		public Component getTreeCellRendererComponent(JTree tree, Object value,
				boolean sel, boolean expanded, boolean leaf, int row,
				boolean hasFocus) {
			super.getTreeCellRendererComponent(tree, value, sel, expanded,
					leaf, row, hasFocus);
			this.setBackgroundNonSelectionColor(new Color(0, 0, 0, 0));
			if (!(value instanceof ComponentNode)) {
				this.setIcon(closedIcon);
			} else if (leaf) {
				this.setIcon(((ComponentNode) value).getIcon());
			}
			return this;
		}
	}
}